import { flushUpdaterQueue, updaterQueue } from "./Component"

export function addEvent(dom, eventName, bindFunction) {
    dom.attach = dom.attach || {}
    dom.attach[eventName] = bindFunction
    // 事件合成机制的核心点一：事件绑定到document上
    if (document[eventName]) {
        return
    }
    document[eventName] = dispatchEvent
}

function dispatchEvent(nativeEvent) {
    updaterQueue.isBatch = true
    // 事件合成机制的核心点2：屏蔽浏览器之间的差异
    const syntheticEvent = createSyntheticEvent(nativeEvent)
    // 事件源
    let target = nativeEvent.target
    while (target) {
        syntheticEvent.currentTarget = target
        let eventName = `on${nativeEvent.type}`
        let bindFunction = target.attach && target.attach[eventName]
        bindFunction && bindFunction(syntheticEvent)
        if (syntheticEvent.isPropagationStopped) {
            break
        }
        target = target.parentNode
    }
    flushUpdaterQueue()
}

// 创建合成事件
function createSyntheticEvent(nativeEvent) {
    let nativeEventKeyValues = {}
    // 把原生事件中的所有方法都挂载到合成事件上
    for (let key in nativeEvent) {
        nativeEventKeyValues[key] = typeof nativeEvent[key] === 'function' ? nativeEvent[key].bind(nativeEvent) : nativeEvent[key]
    }
    // 创建合成事件
    let syntheticEvent = Object.assign(nativeEventKeyValues, {
        nativeEvent,
        isDefaultPrevented: false,
        isPropagationStopped: false,
        preventDefault() {
            this.isDefaultPrevented = true
            if (this.nativeEvent.preventDefault) {
                // 阻止默认行为
                this.nativeEvent.preventDefault()
            } else {
                // IE9以下的阻止默认行为
                this.nativeEvent.returnValue = false
            }
        },
        stopPropation() {
            this.isPropagationStopped = true
            if (this.nativeEvent.stopPropagation) {
                // 阻止事件冒泡
                this.nativeEvent.stopPropagation()
            } else {
                // IE9以下的阻止事件冒泡
                this.nativeEvent.cancelBubble = true
            }
        }
    })
    // 把原生事件中的所有属性都挂载到合成事件上
    return syntheticEvent
}